package org.springrain.javadoc4openapi;

import com.thoughtworks.qdox.model.JavaAnnotation;
import com.thoughtworks.qdox.model.JavaClass;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * java源文件Doc和openapi的处理类
 * <p>
 * 特殊注释注解有:
 *
 * @author springrain
 * @version 0.0.1
 * @required 不能未空, 必填
 * @ignore 忽略字段, 不显示在文档里
 * @todo jsr303, maven插件,配置map深度合并,数组[]支持(isArray仅仅是数组,不是List),get请求不能有requestBody
 * @since 0.0.1
 */
public class JavaDoc4OpenAPI {

    private static final Logger logger = LoggerFactory.getLogger(JavaDoc4OpenAPI.class);
    //所有的javaSource的ConcurrentHashMap<String, JavaClass>对象,key是类的全路径,包括依赖jar包里的类
    public static ConcurrentHashMap<String, JavaClass> javaClassMap = new ConcurrentHashMap<>();
    //controller的注解类,支持生成openapi文档
    private static List<String> controllerClassNameList = new ArrayList<>();

    static {
        controllerClassNameList.add("org.springframework.stereotype.Controller");
        controllerClassNameList.add("org.springframework.web.bind.annotation.RestController");
    }


    //初始化本项目下的所有类文件
    static {
        //List<JavaClass> javaSourceList = new ArrayList<>();

        List<File> projectFiles = JavaSourceUtils.listProjectJavaFile();
        Map<String, JavaClass> javaSourceMap = JavaSourceUtils
                .transforJavaClass(JavaSourceUtils.readJavaFiles(projectFiles));
        javaClassMap.putAll(javaSourceMap);


        //return javaClassMap;
    }


    /**
     * 获取Controller的JavaClassMap
     *
     * @return 返回所有的Controller
     */
    public static List<JavaClass> controllerJavaClassList() {
        //controller的JavaClassList
        List<JavaClass> controllerList = new ArrayList<>();


        for (Map.Entry<String, JavaClass> entry : javaClassMap.entrySet()) {
            JavaClass javaClass = entry.getValue();
            //获取类的所有注解
            List<JavaAnnotation> javaAnnotation = javaClass.getAnnotations();
            if (CollectionUtils.isEmpty(javaAnnotation)) {
                continue;
            }

            for (JavaAnnotation annotation : javaAnnotation) {
                String annotationType = annotation.getType().toString();
                //如果有controller注解
                if (controllerClassNameList.contains(annotationType)) {
                    controllerList.add(javaClass);
                    break;
                }
            }
        }


        return controllerList;

    }

    /**
     * openapi的Map对象,格式化数据的总入口
     *
     * @return 返回openapi的整体对象Map
     */
    public static Map<String, Object> openAPIMap() {
        ConcurrentHashMap<String, Object> openapiMap = new ConcurrentHashMap<>();


        //获取所有的Controller类
        List<JavaClass> controllerJavaClassList = controllerJavaClassList();
        if (CollectionUtils.isEmpty(controllerJavaClassList)) {
            return openapiMap;
        }
        //声明版本协议
        openapiMap.put("openapi", "3.0.0");

        //设置server
        List<Map<String, Object>> serversList = new ArrayList<>();
        Map<String, Object> serverMap = new HashMap<>();
        serverMap.put("url", "http://127.0.0.1:8080");
        serversList.add(serverMap);
        openapiMap.put("servers", serversList);

        //设置info
        Map<String, String> infoMap = new HashMap<>();
        infoMap.put("title", "javadoc4openapi");
        infoMap.put("description", "javadoc4openapi");
        infoMap.put("version", "1.0.0");
        openapiMap.put("info", infoMap);

        //设置tags,一个controller一个tag,用于折叠controller
        List<Map<String, Object>> tagsList = new ArrayList<>();

        //所有的paths
        Map<String, Object> pathsMap = new HashMap<>();

        // 所有的 componentsMap
        Map<String, Object> componentsMap = new ConcurrentHashMap<>();
        //所有的 componentsSchemasMap
        Map<String, Object> componentsSchemasMap = new ConcurrentHashMap<>();
        componentsMap.put("schemas", componentsSchemasMap);

        //JWT验证
        Map<String, Object> securitySchemesMap = new ConcurrentHashMap<>();
        componentsMap.put("securitySchemes", securitySchemesMap);
        Map<String, Object> securitySchemesAPIKeyMap = new ConcurrentHashMap<>();
        securitySchemesMap.put("api_key", securitySchemesAPIKeyMap);
        securitySchemesAPIKeyMap.put("type", "apiKey");
        securitySchemesAPIKeyMap.put("name", "jwtToken");
        securitySchemesAPIKeyMap.put("in", "header");

        //遍历所有的Controller类
        for (JavaClass controllerClass : controllerJavaClassList) {
            //获取java类的注释
            String comment = controllerClass.getComment();
            //设置tag名称和描述
            Map<String, Object> classTagMap = new HashMap<>();
            classTagMap.put("name", controllerClass.getSimpleName());
            if (StringUtils.isNotBlank(comment)) {
                classTagMap.put("description", comment);
            }
            tagsList.add(classTagMap);
            //增加path和componentsSchemasMap
            //核心方法,为每个controller设置path和Component
            OpenAPIUtils.addPathComponentSchema(controllerClass, pathsMap, componentsSchemasMap);
        }
        //设置tags
        openapiMap.put("tags", tagsList);
        //设置paths
        openapiMap.put("paths", pathsMap);
        //设置components
        openapiMap.put("components", componentsMap);

        return openapiMap;

    }


    /**
     * 根据openapi的map,创建openapi文件
     */


    /**
     * 根据openapi的map,创建openapi文件
     */
    public static void makeYamlFileByOpenAPIMap(Map<String, Object> openapiYamlMap, String yamlFilePath) throws IOException {
        FileOutputStream fileOutputStream = null;
        OutputStreamWriter writer = null;
        try {
            DumperOptions dumperOptions = new DumperOptions();
            dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
            dumperOptions.setDefaultScalarStyle(DumperOptions.ScalarStyle.PLAIN);
            dumperOptions.setPrettyFlow(false);
            Yaml yaml = new Yaml(dumperOptions);

            File dumpfile = new File(yamlFilePath);
            if (!dumpfile.exists()) {
                dumpfile.createNewFile();
            }
            fileOutputStream = new FileOutputStream(dumpfile);
            writer = new OutputStreamWriter(fileOutputStream);
            //Map<String, Object> openapiYamlMap = openapiYamlMap();
            yaml.dump(openapiYamlMap, writer);

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (writer != null) {
                writer.close();
            }
            if (fileOutputStream != null) {
                fileOutputStream.close();
            }
        }


    }


}
